home *** CD-ROM | disk | FTP | other *** search
- unit COMDragDropSupport;
-
- interface
-
- uses
- Forms, ActiveX, Classes, Windows, ShellAPI, Graphics;
-
- type
- //When adding to this set, update the GetDataFormats function as well
- TDataFormat = (dfText, dfHDrop, dfDIB, dfBitmap, dfPalette,
- dfWMF, dfEMF, dfRTF, dfFileName, dfShellIDList,
- dfObjectDescriptor, dfLinkSrcDescriptor);
- TDataFormats = set of TDataFormat;
-
- TDataObject = class
- private
- FDataObject: IDataObject;
- FFormatEtc: TFormatEtc;
- FDataFormats: TDataFormats;
- //Stores data object's data formats in FDataFormats
- procedure GetDataFormats;
- procedure SetupFormatEtc(ClipFmt: TClipFormat; TyMed: Longint);
- procedure GetDescriptor(SM: TStgMedium; List: TStrings);
- public
- constructor Create(DataObj: IDataObject);
- procedure GetDataAsBitmap(Bmp: TBitmap);
- procedure GetDataAsDIB(Bmp: TBitmap);
- procedure GetDataAsHDrop(FileList: TStrings);
- procedure GetDataAsWMF(MetaFile: TMetaFile);
- procedure GetDataAsEMF(MetaFile: TMetafile);
- procedure GetDataAsPalette(Bmp: TBitmap);
- procedure GetDataAsRTF(var Txt: String);
- procedure GetDataAsText(var Txt: String);
- procedure GetDataAsFileName(var Txt: String);
- procedure GetDataAsShellIDList(IDList: TStrings);
- procedure GetDataAsObjectDescriptor(ObjDescList: TStrings);
- procedure GetDataAsLinkSrcDescriptor(LinkSrcDescList: TStrings);
- procedure ListFormats(List: TStrings);
- property DataFormats: TDataFormats read FDataFormats;
- end; //TDataObject
-
- //Turn clipboard format constant into the appropriate descriptive string
- function ClipFormatToStr(Fmt: TClipFormat): String;
- //Turn a storage medium type constant into descriptive string
- function TyMedToStr(TyMed: Longint): String;
-
- implementation
-
- uses
- ClipBrd, ComObj, SysUtils, ShlObj;
-
- var
- CF_RTF,
- CF_FILENAME,
- CF_IDLIST,
- CF_OBJECTDESCRIPTOR,
- CF_LINKSRCDESCRIPTOR: TClipFormat;
-
- function ClipFormatToStr(Fmt: TClipFormat): String;
- var
- Buf: array[0..255] of Char;
- begin
- GetClipboardFormatName(Fmt, Buf, SizeOf(Buf));
- Result := String(Buf);
- if Result = '' then
- case Fmt of
- CF_TEXT: Result := 'CF_TEXT';
- CF_BITMAP: Result := 'CF_BITMAP';
- CF_METAFILEPICT: Result := 'CF_METAFILEPICT';
- CF_SYLK: Result := 'CF_SYLK';
- CF_DIF: Result := 'CF_DIF';
- CF_TIFF: Result := 'CF_TIFF';
- CF_OEMTEXT: Result := 'CF_OEMTEXT';
- CF_DIB: Result := 'CF_DIB';
- CF_PALETTE: Result := 'CF_PALETTE';
- CF_PENDATA: Result := 'CF_PENDATA';
- CF_RIFF: Result := 'CF_RIFF';
- CF_WAVE: Result := 'CF_WAVE';
- CF_UNICODETEXT: Result := 'CF_UNICODETEXT';
- CF_ENHMETAFILE: Result := 'CF_ENHMETAFILE';
- CF_HDROP: Result := 'CF_HDROP';
- CF_LOCALE: Result := 'CF_LOCALE';
- CF_OWNERDISPLAY: Result := 'CF_OWNERDISPLAY';
- CF_DSPTEXT: Result := 'CF_DSPTEXT';
- CF_DSPBITMAP: Result := 'CF_DSPBITMAP';
- CF_DSPMETAFILEPICT: Result := 'CF_DSPMETAFILEPICT';
- CF_DSPENHMETAFILE: Result := 'CF_DSPENHMETAFILE';
- else
- Result := 'Unknown clipboard format'
- end
- end;
-
- function TyMedToStr(TyMed: Longint): String;
- begin
- Result := 'Unknown medium type';
- case TyMed of
- TYMED_NULL: Result := 'TYMED_NULL';
- TYMED_HGLOBAL: Result := 'TYMED_HGLOBAL';
- TYMED_FILE: Result := 'TYMED_FILE';
- TYMED_ISTREAM: Result := 'TYMED_ISTREAM';
- TYMED_ISTORAGE: Result := 'TYMED_ISTORAGE';
- TYMED_GDI: Result := 'TYMED_GDI';
- TYMED_MFPICT: Result := 'TYMED_MFPICT';
- TYMED_ENHMF: Result := 'TYMED_ENHMF';
- end;
- end;
-
- { TDataObject }
-
- constructor TDataObject.Create(DataObj: IDataObject);
- begin
- inherited Create;
- FDataObject := DataObj;
- GetDataFormats
- end;
-
- procedure TDataObject.GetDataFormats;
-
- procedure GetDataFormat(ClipFmt: TClipFormat; TyMed: Longint; Format: TDataFormat);
- begin
- SetupFormatEtc(ClipFmt, TyMed);
- if FDataObject.QueryGetData(FFormatEtc) = S_OK then
- Include(FDataFormats, Format);
- end;
-
- begin
- FDataFormats := [];
- GetDataFormat(CF_BITMAP, TYMED_GDI, dfBitmap);
- GetDataFormat(CF_DIB, TYMED_HGLOBAL, dfDIB);
- GetDataFormat(CF_HDROP, TYMED_HGLOBAL, dfHDrop);
- GetDataFormat(CF_METAFILEPICT, TYMED_MFPICT, dfWMF);
- GetDataFormat(CF_ENHMETAFILE, TYMED_ENHMF, dFEMF);
- GetDataFormat(CF_PALETTE, TYMED_GDI, dfPalette);
- GetDataFormat(CF_TEXT, TYMED_HGLOBAL, dfText);
- GetDataFormat(CF_RTF, TYMED_HGLOBAL, dfRTF);
- GetDataFormat(CF_FILENAME, TYMED_HGLOBAL, dfFileName);
- GetDataFormat(CF_IDLIST, TYMED_HGLOBAL, dfShellIDList);
- GetDataFormat(CF_OBJECTDESCRIPTOR, TYMED_HGLOBAL, dfObjectDescriptor);
- GetDataFormat(CF_LINKSRCDESCRIPTOR, TYMED_HGLOBAL, dfLinkSrcDescriptor);
- end;
-
- procedure TDataObject.ListFormats(List: TStrings);
- var
- EFE: IEnumFormatEtc;
- FE: TFormatEtc;
- CElt: Longint;
- begin
- if not Assigned(List) then
- Exit;
- OleCheck(FDataObject.EnumFormatEtc(DATADIR_GET, EFE));
- List.Clear;
- repeat
- OleCheck(EFE.Next(1, FE, @CElt));
- if CElt > 0 then
- List.Add(Format('%s (%s)',
- [ClipFormatToStr(FE.cfFormat),
- TyMedToStr(FE.tymed)]));
- until CElt = 0;
- end;
-
- procedure TDataObject.SetupFormatEtc(ClipFmt: TClipFormat; TyMed: Longint);
- begin
- FFormatEtc.cfFormat := ClipFmt;
- FFormatEtc.tymed := TyMed;
- FFormatEtc.ptd := nil;
- FFormatEtc.dwAspect := DVASPECT_CONTENT;
- FFormatEtc.lindex := -1;
- end;
-
- procedure TDataObject.GetDataAsBitmap(Bmp: TBitmap);
- var
- SM: TStgMedium;
- begin
- if not Assigned(Bmp) then
- Exit;
- SetupFormatEtc(CF_BITMAP, TYMED_GDI);
- OleCheck(FDataObject.GetData(FFormatEtc, SM));
- try
- //Use a handy shortcut to load bitmp
- Bmp.LoadFromClipboardFormat(CF_BITMAP, SM.hBitmap, 0);
- if dfPalette in DataFormats then
- GetDataAsPalette(Bmp)
- finally
- ReleaseStgMedium(SM)
- end
- end;
-
- procedure TDataObject.GetDataAsDIB(Bmp: TBitmap);
- var
- SM: TStgMedium;
- Stream: TMemoryStream;
- DIBPtr: Pointer;
- DIBSize: DWord;
- BMF: TBitmapFileHeader;
- begin
- if not Assigned(Bmp) then
- Exit;
- SetupFormatEtc(CF_DIB, TYMED_HGLOBAL);
- OleCheck(FDataObject.GetData(FFormatEtc, SM));
- try
- DIBSize := GlobalSize(SM.hGlobal);
- DIBPtr := GlobalLock(SM.hGlobal);
- try
- Stream := TMemoryStream.Create;
- try
- //Write a bitmap file header record
- FillChar(BMF, sizeof(BMF), 0);
- BMF.bfType := $4D42;
- BMF.bfSize := SizeOf(BMF) + DIBSize;
- Stream.Write(BMF, SizeOf(BMF));
- //Follow the BMF with the DIB
- Stream.Write(DIBPtr^, DIBSize);
- Stream.Position := 0;
- //Load the finished DIB into a TBitmap
- Bmp.LoadFromStream(Stream)
- finally
- Stream.Free
- end
- finally
- GlobalUnlock(SM.hGlobal)
- end
- finally
- ReleaseStgMedium(SM)
- end
- end;
-
- procedure TDataObject.GetDataAsHDrop(FileList: TStrings);
- var
- SM: TStgMedium;
- Count, Loop: Integer;
- Buf: array[0..1023] of Char;
- begin
- if not Assigned(FileList) then
- Exit;
- SetupFormatEtc(CF_HDROP, TYMED_HGLOBAL);
- OleCheck(FDataObject.GetData(FFormatEtc, SM));
- try
- //How many files were dragged?
- Count := DragQueryFile(SM.hGlobal, Cardinal(-1), nil, 0);
- FileList.BeginUpdate;
- try
- FileList.Clear;
- //Loop through files
- for Loop := 0 to Pred(Count) do
- begin
- //Get filename
- DragQueryFile(SM.hGlobal, Loop, Buf, SizeOf(Buf));
- FileList.Add(Buf)
- end
- finally
- FileList.EndUpdate
- end
- finally
- ReleaseStgMedium(SM)
- end
- end;
-
- procedure TDataObject.GetDataAsWMF(MetaFile: TMetaFile);
- var
- SM: TStgMedium;
- MPPtr: PMetaFilePict;
- MFBufSize: DWord;
- MFBuf: Pointer;
- begin
- if not Assigned(MetaFile) then
- Exit;
- SetupFormatEtc(CF_METAFILEPICT, TYMED_MFPICT);
- OleCheck(FDataObject.GetData(FFormatEtc, SM));
- try
- //Get access to the TMetaFilePict record
- MPPtr := GlobalLock(SM.hMetaFilePict);
- try
- //How big is the metafile?
- MFBufSize := GetMetaFileBitsEx(MPPtr^.hMF, 0, nil);
- //Allocate sufficient buffer space
- GetMem(MFBuf, MFBufSize);
- try
- //Copy metafile to buffer
- Win32Check(LongBool(
- GetMetaFileBitsEx(MPPtr^.hMF, MFBufSize, MFBuf)));
- //Generate enhanced metafile from buffer
- MetaFile.Handle := SetWinMetaFileBits(MFBufSize, MFBuf, 0, MPPtr^)
- finally
- //Free buffer
- FreeMem(MFBuf)
- end
- finally
- //Unlock memory handle
- GlobalUnlock(SM.hMetaFilePict)
- end
- finally
- ReleaseStgMedium(SM)
- end
- end;
-
- procedure TDataObject.GetDataAsEMF(MetaFile: TMetafile);
- var
- SM: TStgMedium;
- begin
- if not Assigned(MetaFile) then
- Exit;
- SetupFormatEtc(CF_ENHMETAFILE, TYMED_ENHMF);
- OleCheck(FDataObject.GetData(FFormatEtc, SM));
- try
- MetaFile.Handle := CopyEnhMetafile(SM.hEnhMetaFile, nil)
- finally
- ReleaseStgMedium(SM)
- end
- end;
-
- procedure TDataObject.GetDataAsPalette(Bmp: TBitmap);
- var
- SM: TStgMedium;
- begin
- if not Assigned(Bmp) then
- Exit;
- SetupFormatEtc(CF_PALETTE, TYMED_GDI);
- OleCheck(FDataObject.GetData(FFormatEtc, SM));
- try
- Bmp.Palette := CopyPalette(SM.hBitmap)
- finally
- ReleaseStgMedium(SM)
- end
- end;
-
- procedure TDataObject.GetDataAsText(var Txt: String);
- var
- SM: TStgMedium;
- CTxt: PChar;
- begin
- SetupFormatEtc(CF_TEXT, TYMED_HGLOBAL);
- OleCheck(FDataObject.GetData(FFormatEtc, SM));
- try
- CTxt := GlobalLock(SM.hGlobal);
- try
- Txt := String(CTxt);
- finally
- GlobalUnlock(SM.hGlobal);
- end
- finally
- ReleaseStgMedium(SM)
- end
- end;
-
- procedure TDataObject.GetDataAsRTF(var Txt: String);
- var
- SM: TStgMedium;
- CTxt: PChar;
- begin
- SetupFormatEtc(CF_RTF, TYMED_HGLOBAL);
- OleCheck(FDataObject.GetData(FFormatEtc, SM));
- try
- CTxt := GlobalLock(SM.hGlobal);
- try
- Txt := String(CTxt);
- finally
- GlobalUnlock(SM.hGlobal);
- end
- finally
- ReleaseStgMedium(SM)
- end
- end;
-
- procedure TDataObject.GetDataAsFileName(var Txt: String);
- var
- SM: TStgMedium;
- CTxt: PChar;
- begin
- SetupFormatEtc(CF_FILENAME, TYMED_HGLOBAL);
- OleCheck(FDataObject.GetData(FFormatEtc, SM));
- try
- CTxt := GlobalLock(SM.hGlobal);
- try
- Txt := String(CTxt);
- finally
- GlobalUnlock(SM.hGlobal);
- end
- finally
- ReleaseStgMedium(SM)
- end
- end;
-
- {$RangeChecks Off}
- procedure TDataObject.GetDataAsShellIDList(IDList: TStrings);
- var
- SM: TStgMedium;
- IDA: PIDA;
- PIDL: PItemIDList;
- Loop: Integer;
- FileInfo: TSHFileInfo;
- ParentFolder: String;
- begin
- SetupFormatEtc(CF_IDLIST, TYMED_HGLOBAL);
- OleCheck(FDataObject.GetData(FFormatEtc, SM));
- try
- IDA := GlobalLock(SM.hGlobal);
- try
- IDList.Clear;
- for Loop := 0 to IDA.cidl do
- begin
- PIDL := PItemIDList(DWord(IDA) + IDA.aoffset[Loop]);
- SHGetFileInfo(PChar(PIDL), 0, FileInfo, SizeOf(FileInfo),
- SHGFI_PIDL or SHGFI_DISPLAYNAME);
- if Loop = 0 then
- ParentFolder := FileInfo.szDisplayName
- else
- if StrLen(FileInfo.szDisplayName) > 0 then
- IDList.Add(ParentFolder + '\' + FileInfo.szDisplayName);
- end
- finally
- GlobalUnlock(SM.hGlobal);
- end
- finally
- ReleaseStgMedium(SM)
- end
- end;
- {$RangeChecks On}
-
- procedure TDataObject.GetDescriptor(SM: TStgMedium; List: TStrings);
- var
- ObjDesc: PObjectDescriptor;
- Txt: String;
- begin
- ObjDesc := GlobalLock(SM.hGlobal);
- try
- List.Clear;
- List.Add(Format('%s', [ClassIDToProgID(ObjDesc.clsid)]));
- List.Add(Format('%s', [GuidToString(ObjDesc.clsid)]));
- case ObjDesc.dwDrawAspect of
- 0: List.Add('App didn''t originally draw object');
- DVASPECT_CONTENT: List.Add('Can be displayed as embedded content');
- DVASPECT_ICON: List.Add('Iconic representation');
- end;
- List.Add(Format('Object extent: (%d,%d)',
- [ObjDesc.size.x, ObjDesc.size.y]));
- List.Add(Format('Object was clicked at: (%d,%d)',
- [ObjDesc.point.x, ObjDesc.point.y]));
- if ObjDesc.dwStatus <> 0 then
- begin
- List.Add(Format('Characteristics: ($%x)', [ObjDesc.dwStatus]));
- if ObjDesc.dwStatus and OLEMISC_RECOMPOSEONRESIZE <> 0 then
- List.Add(' Object wants to take charge of resizing image');
- if ObjDesc.dwStatus and OLEMISC_ONLYICONIC <> 0 then
- List.Add(' No useful content apart from icon');
- if ObjDesc.dwStatus and OLEMISC_INSERTNOTREPLACE <> 0 then
- List.Add(' Object initialised itself from data in container''s current selection');
- if ObjDesc.dwStatus and OLEMISC_STATIC <> 0 then
- List.Add(' Static object (no data, only presentation)');
- if ObjDesc.dwStatus and OLEMISC_CANTLINKINSIDE <> 0 then
- List.Add(' Cannot be link source that, when bound to, runs the object');
- if ObjDesc.dwStatus and OLEMISC_CANLINKBYOLE1 <> 0 then
- List.Add(' Can be linked to by OLE 1 containers');
- if ObjDesc.dwStatus and OLEMISC_ISLINKOBJECT <> 0 then
- List.Add(' This is a link object');
- if ObjDesc.dwStatus and OLEMISC_INSIDEOUT <> 0 then
- List.Add(' Can be activated in-place without menus or toolbars');
- if ObjDesc.dwStatus and OLEMISC_ACTIVATEWHENVISIBLE <> 0 then
- List.Add(' Should be activated whenever visible');
- if ObjDesc.dwStatus and OLEMISC_RENDERINGISDEVICEINDEPENDENT <> 0 then
- List.Add(' Appearance will be identical on all target devices');
- end;
- if ObjDesc.dwFullUserTypeName = 0 then
- Txt := 'unknown user type'
- else
- Txt := String(PWideChar(DWord(ObjDesc) + DWord(ObjDesc.dwFullUserTypeName)));
- List.Add(Format('Full user type: %s', [Txt]));
- if ObjDesc.dwSrcOfCopy = 0 then
- Txt := 'unknown source'
- else
- Txt := String(PWideChar(DWord(ObjDesc) + DWord(ObjDesc.dwSrcOfCopy)));
- List.Add(Format('Transfer source: %s',
- [Txt]));
- finally
- GlobalUnlock(SM.hGlobal);
- end
- end;
-
- procedure TDataObject.GetDataAsObjectDescriptor(ObjDescList: TStrings);
- var
- SM: TStgMedium;
- begin
- SetupFormatEtc(CF_OBJECTDESCRIPTOR, TYMED_HGLOBAL);
- OleCheck(FDataObject.GetData(FFormatEtc, SM));
- try
- GetDescriptor(SM, ObjDescList)
- finally
- ReleaseStgMedium(SM)
- end
- end;
-
- procedure TDataObject.GetDataAsLinkSrcDescriptor(
- LinkSrcDescList: TStrings);
- var
- SM: TStgMedium;
- begin
- SetupFormatEtc(CF_LINKSRCDESCRIPTOR, TYMED_HGLOBAL);
- OleCheck(FDataObject.GetData(FFormatEtc, SM));
- try
- GetDescriptor(SM, LinkSrcDescList)
- finally
- ReleaseStgMedium(SM)
- end
- end;
-
- initialization
- CF_FILENAME := RegisterClipboardFormat('FileName');
- CF_RTF := RegisterClipboardFormat('Rich Text Format');
- CF_IDLIST := RegisterClipboardFormat(CFSTR_SHELLIDLIST);
- CF_OBJECTDESCRIPTOR := RegisterClipboardFormat('Object Descriptor');
- CF_LINKSRCDESCRIPTOR := RegisterClipboardFormat('Link Source Descriptor');
- end.
-